<?php

namespace App\Dao;

use App\Channels\HbWxChannel;
use App\Exceptions\ApiErrorException;
use App\Models\ChildrenPlayItem;
use App\Models\ChildrenPlayOrder;
use App\Models\ChildrenPlayYear;
use App\Models\ChildrenPlayYearCardConsumeLog;
use App\Models\ChildrenPlayYearOrder;
use App\Models\Payment;
use App\Models\TeamInfo;
use App\Models\TicketDateTimeperiod;
use App\Models\TicketOrder;
use App\Models\TicketOrderItem;
use App\Models\TicketOrderItemLog;
use App\Models\TicketOrderItemTeam;
use App\Models\TicketOrderTeamPlist;
use App\Models\TicketOrderLog;
use App\Models\TicketOrderRefundLog;
use App\Models\TicketPayment;
use App\Models\TicketVisitorInfo;
use App\Models\TicketYearCard;
use App\Models\TicketYearCardOrder;
use App\Models\Users;
use App\Models\UsersBind;
use App\Models\Donates;
use App\Utilities\SmsAPIDemo\lib\SmsSendConn;
use Carbon\Carbon;
use EasyWeChat\Factory;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

/**
 * 门票订单业务模型
 *
 * @author lxp 20170814
 */
class payDao extends Donates
{
    /**
     * 生成订单号
     *
     * @return string
     * @author lxp 20180505
     */
    public static function get_order_sn()
    {
        $order_sn = 'SHJY' . date('ymdHi') . rand(1000, 9999);
        if (Donates::where('order_sn', $order_sn)->count() > 0) {
            return self::get_order_sn();
        } else {
            return $order_sn;
        }
    }

    /**
     * 生成订单
     *
     * @param int $order_type 订单类型，1散客，2团体
     * @param array $order_data 订单数据
     * @param array $toi_data 订单门票数据
     * @param int $order_create_type 订单产生类型
     * @return TicketOrder
     * @throws ApiErrorException
     * @throws \Exception
     * @author lxp 20180504
     */
    public static function order($order_type, $order_data, $toi_data, $order_create_type = ORDER_CREATE_YY)
    {
        // 防止重复下单，一分钟
        $orderKey = md5($order_type . json_encode($order_data) . json_encode($toi_data));
        if (cache($orderKey)) {
            throw new ApiErrorException('请不要重复提交，稍后再试');
        } else {
            cache([
                $orderKey => 1
            ], Carbon::now()->addSeconds(60));
        }

        return DB::transaction(function () use ($order_type, $order_data, $toi_data, $order_create_type) {
            $uid = $order_data['uid'];
            $t_date = $order_data['t_date'];
            //总订单价格
            $order_amount = $order_data['order_amount'];

            $is_parent = isset($order_data['is_parent']) ? $order_data['is_parent'] : 1;
            $is_children_play = isset($order_data['is_children_play']) ? $order_data['is_children_play'] : 1;
            $payment_id = isset($order_data['payment_id']) ? $order_data['payment_id'] : 0;
            //总人数
            $people_num = isset($order_data['people_num']) ? $order_data['people_num'] : 1;
            //优惠人数
            $discount_num = isset($order_data['discount_num']) ? $order_data['discount_num'] : 0;
            //年卡订单id
            $year_torder_id = isset($order_data['year_torder_id']) ? $order_data['year_torder_id'] : 0;
            //年卡优惠金额
            $discount_price_count = isset($order_data['discount_price_count']) ? $order_data['discount_price_count'] : 0;
            $ticket_create_type = isset($order_data['ticket_create_type']) ? $order_data['ticket_create_type'] : 0;
            $time_period = isset($order_data['time_period']) ? $order_data['time_period'] : '';
            $time_now = date('Y-m-d H:i:s');
            $contact_phone = isset($order_data['contact_phone']) ? $order_data['contact_phone'] : null;
            $plist = isset($order_data['plist']) ? $order_data['plist'] : [];

            switch ($order_type) {
                case ORDER_TYPE_PERSON:
                    // 散客订单初始状态为待支付
                    $order_status = T_ORDER_UNPAY;
                    break;
                case ORDER_TYPE_TEAM:
                    // 团体订单初始状态为待审核
                    $order_status = T_ORDER_UNCHECKED;
                    break;
                default:
                    throw new ApiErrorException('Empty order type');
                    break;
            }

//            $order = TicketOrder::create([
//			    'order_type'=>$order_type,
//			    'is_parent'=>$is_parent,
//			    'order_create_type'=>$order_create_type,
//			    'is_children_play'=>$is_children_play,
//			    't_date'=>$t_date,
//			    'order_sn'=>TicketOrderDao::get_order_sn(),
//			    'uid'=>$uid,
//			    'order_amount'=>$order_amount,
//			    'people_num'=>$people_num,
//			    'order_status'=>$order_status,
//			    'add_time'=>$time_now,
//			    'plat'=> request('p', ''),
//			    'time_period'=>$time_period,
//			    'contact_phone'=>$contact_phone,
//			    'seller_id'=>$seller_id,
//            ]);
            // 生成订单

            $order = new TicketOrder();
            $order->order_type = $order_type;
            $order->is_parent = $is_parent;
            $order->order_create_type = $order_create_type;
            $order->is_children_play = $is_children_play;
            $order->t_date = $t_date;
            $order->order_sn = TicketOrderDao::get_order_sn();
            $order->uid = $uid;
            $order->order_amount = $order_amount;
            $order->people_num = $people_num;
            $order->order_status = $order_status;
            $order->add_time = $time_now;
            $order->plat = request('p', '');
            $order->time_period = $time_period;
            $order->contact_phone = $contact_phone;
            if ($order_create_type == ORDER_CREATE_NYY && Auth::check()) {
                // 人工售票，记录售票员id
                $order->seller_id = Auth::user()->uid;
            }
            $order->save();
            $torder_id = TicketOrder::where('order_sn', $order->order_sn)->value('torder_id');

            if (!$torder_id) {
                throw new ApiErrorException('生成订单失败，请稍后重试');
            }

            //是否使用年卡
            $is_year_card = 0;
            //记录年卡消费信息
            if ($discount_num > 0 && $year_torder_id != 0) {
                ChildrenPlayYearCardConsumeLog::create([
                    'order_create_type' => $order_create_type,
                    'year_torder_id' => $year_torder_id,
                    'uid' => $uid,
                    'torder_id' => $torder_id,
                    'consume_num' => $discount_num,
                    'consume_status' => YEAR_CARD_UNCONSUME,
                    'discount_price_count' => $discount_price_count,
                    'add_time' => $time_now
                ]);
                //用过次数
                ChildrenPlayYearOrder::where('torder_id', $year_torder_id)->increment('used_num', $discount_num);
                //剩余次数
                ChildrenPlayYearOrder::where('torder_id', $year_torder_id)->decrement('surplus_num', $discount_num);
                $is_year_card = 1;
            }


            // 插入门票信息
            switch ($order_type) {
                case ORDER_TYPE_PERSON:
                    // 散客
                    foreach ($toi_data as $toi) {

                        $titem1 = new  TicketOrderItem();
                        $titem1->ticket_create_type = $ticket_create_type;
                        $titem1->torder_id = $torder_id;
                        //是儿童乐园门票 1不是 2是
                        $titem1->is_children_play = isset($toi['is_children_play']) ? $toi['is_children_play'] : 1;
                        $titem1->ticket_id = $toi['ticket_id'];
                        $titem1->td_id = $toi['td_id'];
                        $titem1->td_tp_id = $toi['td_tp_id'];
                        $titem1->discount_price = $toi['discount_price'];
                        $titem1->default_price = $toi['default_price'];
                        $titem1->member_price = $toi['member_price'];
                        $titem1->toi_status = TICKET_UNPAY;
                        $titem1->pt_id = $toi['pt_id'];
                        $titem1->toi_id = isset($toi['toi_id']) ? $toi['toi_id'] : 0;
                        $titem1->u_city = isset($toi['u_city']) ? $toi['u_city'] : null;
                        $titem1->u_age = isset($toi['u_age']) ? $toi['u_age'] : null;
                        $titem1->u_sex = isset($toi['u_sex']) ? $toi['u_sex'] : null;
                        $titem1->save();

                        // 更新门票时段票量
                        TicketDateTimeperiod::where('td_tp_id', $toi['td_tp_id'])->increment('tp_count');
                        if (isset($toi['parent']) && count($toi['parent']) > 0) {
                            $titem = new  TicketOrderItem();
                            $titem->ticket_create_type = $ticket_create_type;
                            $titem->torder_id = $torder_id;
                            //是儿童乐园门票 1不是 2是
                            $titem->is_children_play = isset($toi['parent'][0]['is_children_play']) ? $toi['parent'][0]['is_children_play'] : 2;
                            //父类门票id
                            $titem->parent_titem_id = $titem1->titem_id;
                            $titem->is_year_card = $is_year_card;
                            $titem->ticket_id = $toi['parent'][0]['ticket_id'];
                            $titem->td_id = $toi['parent'][0]['td_id'];
                            $titem->td_tp_id = $toi['parent'][0]['td_tp_id'];
                            $titem->discount_price = $toi['parent'][0]['discount_price'];
                            $titem->default_price = $toi['parent'][0]['default_price'];
                            $titem->member_price = $toi['parent'][0]['member_price'];
                            $titem->toi_status = TICKET_UNPAY;
                            $titem->pt_id = $toi['parent'][0]['pt_id'];
                            $titem->toi_id = isset($toi['parent'][0]['toi_id']) ? $toi['parent'][0]['toi_id'] : 0;
                            $titem->u_city = isset($toi['parent'][0]['u_city']) ? $toi['parent'][0]['u_city'] : null;
                            $titem->u_age = isset($toi['parent'][0]['u_age']) ? $toi['parent'][0]['u_age'] : null;
                            $titem->u_sex = isset($toi['parent'][0]['u_sex']) ? $toi['parent'][0]['u_sex'] : null;
                            $titem->save();
                            // 更新儿童门票时段票量
                            TicketDateTimeperiod::where('td_tp_id', $toi['parent'][0]['td_tp_id'])->increment('tp_count');
                        }

                    }


                    if ($order_amount == 0) {
                        // 散客门票如不需要支付，订单完成
                        $order = TicketOrderDao::finish($torder_id);
                    }
                    break;
            }

            return $order;
        });
    }

    /**
     * 订单完成
     *
     * @param int $torder_id 订单id
     * @param int $payment_id 支付方式id
     * @param bool $paysuccess 是否为支付成功订单
     * @param string $remark 订单备注
     * @param int $is_zd 订单详情中主动查询不更改门票号 1主动
     * @return mixed
     * @author lxp 20180505
     */
    public static function finish($torder_id, $payment_id = 0, $paysuccess = false, $remark = '',$is_zd=0)
    {
        return DB::transaction(function () use ($torder_id, $payment_id, $paysuccess, $remark,$is_zd) {
            $time_now = date('Y-m-d H:i:s');

            // 修改订单状态
            $torder = TicketOrder::select([
                'torder_id',
                'order_type',
                'order_create_type',
                'order_status',
                'uid',
                't_date',
                'order_sn',
                'time_period',
                'is_parent',
                'people_num',
                'contact_phone',
                'order_sn',
                'order_amount',
                'add_time',
                'contact_phone',
                't_date',
                'is_parent',
                'out_trade_no',
                'payment_id'

            ])->findOrFail($torder_id);
            $order_status_old = $torder->order_status;
            // 待支付（或已取消） -> 完成
            self::check_order_status($order_status_old, T_ORDER_FINISH);
            $torder->order_status = T_ORDER_FINISH;
            $torder->finish_time = $time_now;
            $torder->payment_id = $payment_id;
            if ($paysuccess) {
                $torder->pay_time = $time_now;
            }
            $torder->save();

            // 添加状态改变日志
            TicketOrderLogDao::ticket_order_log($torder_id, $order_status_old, T_ORDER_FINISH, $remark);

            switch ($torder->order_type) {
                case ORDER_TYPE_PERSON:
                    // 处理散客门票
                    $ticket_items = TicketOrderItem::where('torder_id', $torder_id)->get([
                        'titem_id',
                        'toi_status',
                        'ticket_id',
                        'td_tp_id',
                        'toi_id'
                    ]);
                    $ticket_items->each(function ($item) use ($torder, $time_now, &$time_period, $order_status_old,$is_zd) {
                        $toi_status_old = $item->toi_status;
                        if($is_zd==0){
                            // 生成门票号
                            $item->toi_sn = TicketOrderItemDao::get_toi_sn($torder->order_type);
                        }

                        // 更改门票状态为待取票
                        $item->toi_status = TICKET_UNGET;
                        // 门票生成时间
                        $item->i_add_time = $time_now;
                        $item->save();

                        // 添加门票状态改变日志
                        TicketOrderItemLogDao::ticket_order_item_log($item->titem_id, $toi_status_old, $item->toi_status, 0, '');

                        // 订单从取消变为支付完成，需要加回预约数量
                        if ($order_status_old == T_ORDER_CANCELED) {
                            TicketDateTimeperiod::where('td_tp_id', $item->td_tp_id)->increment('tp_count');
                        }
                    });
                    break;
                case ORDER_TYPE_TEAM:
                    // 处理团体门票
                    $team_titems = TicketOrderItemTeam::where('torder_id', $torder_id)->get([
                        'titem_team_id',
                        'ticket_id',
                        'td_tp_id'
                    ]);
                    foreach ($team_titems as $team_titem) {
                        if($is_zd==0){
                            // 生成门票号
                            $team_titem->toi_sn = TicketOrderItemDao::get_toi_sn($torder->order_type);
                        }
                        // 更改门票状态为待取票
                        $team_titem->toi_status = TICKET_UNGET;
                        // 门票生成时间
                        $team_titem->i_add_time = $time_now;
                        $team_titem->save();

                        // 订单从取消变为支付完成，需要加回预约数量
                        if ($order_status_old == T_ORDER_CANCELED) {
                            TicketDateTimeperiod::where('td_tp_id', $team_titem->td_tp_id)->increment('tp_count', $torder->people_num);
                            // 更新团体预约个数
                            TicketDateTimeperiod::where('td_tp_id', $team_titem->td_tp_id)->increment('tp_count_n');
                        }
                    }
                    break;
                default:
                    throw new ApiErrorException();
                    break;
            }
            // 发送短信
            $smssend = new SmsSendConn();
            $content = "门票预订成功，入馆时间" . $torder->t_date . ' ' . $torder->time_period . "，共" . $torder->people_num . "人，订单号" . $torder->order_sn . "，参观时请携带订单内的相关证件。";
            $a = $smssend->singleSend(['mobile' => $torder->contact_phone, 'content' => $content]);
            $logObj = app('logext');
            $logObj->init('ticket_duanxin_result');
            $logObj->logbuffer('mobile', $torder->contact_phone);
            $logObj->logbuffer('result', json_encode($a));
            $logObj->logend();
            return $torder;
        });
    }

    /**
     * 取消未支付的订单
     *
     * @param int $torder_id
     * @author lxp 20180507
     */
    public static function cancel($torder_id)
    {
        DB::transaction(function () use ($torder_id) {
            $time_now = date('Y-m-d H:i:s');

            // 订单状态变为取消
            $torder = TicketOrder::select([
                'torder_id',
                'order_status',
                'order_type',
                'people_num',
                'order_create_type',
                'is_parent',
                'payment_id'
            ])->findOrFail($torder_id);
            // 取得支付方式
            $payment = TicketPayment::select(['payment_info'])->find($torder->payment_id);
            if (!is_null($payment)) {
                $payment_info = unserialize($payment->payment_info);

                // 到支付平台查询订单状态
                switch ($torder->payment_id) {
                    case PAYMENT_ID_WXPAY:
                        $wxapp = Factory::payment([
                            'app_id' => $payment_info['wxAppId'],
                            'mch_id' => $payment_info['wxMchId'],
                            'key' => $payment_info['wxkey']
                        ]);
                        // 判断外部订单状态
                        if ($torder->out_trade_no) {
                            $query_result = $wxapp->order->queryByOutTradeNumber($torder->out_trade_no);
                            if (isset($query_result['return_code']) && $query_result['return_code'] == 'SUCCESS' && isset($query_result['trade_state']) && $query_result['trade_state'] == 'SUCCESS') {
                                // 支付成功，订单完成
                                return self::finish($torder->torder_id, PAYMENT_ID_WXPAY, true, '通知超时，主动查询');
                            }
                        }
                        break;
                    case PAYMENT_ID_ALIPAY:
                        $alipay = new \App\Utilities\Alipay\AopClient();
                        $alipay->appId = $payment_info['appId'];
                        $alipay->signType = 'RSA2';
                        $alipay->rsaPrivateKey = file_get_contents($payment_info['private_key_path']);
                        $alipay->alipayrsaPublicKey = file_get_contents($payment_info['public_key_path']);
                        $alipay_query = new \App\Utilities\Alipay\Request\AlipayTradeQueryRequest();
                        $data['out_trade_no'] = $torder->out_trade_no;
                        $alipay_query->setBizContent(json_encode($data));
                        $result = $alipay->execute($alipay_query);
                        $responseNode = str_replace(".", "_", $alipay_query->getApiMethodName()) . "_response";
                        $resultCode = $result->$responseNode->code;
                        if (!empty($resultCode) && $resultCode == 10000) {
                            $resultStatus = $result->$responseNode->trade_status;
                            if(in_array($resultStatus,["TRADE_SUCCESS","TRADE_FINISHED"])){
                                // 支付成功，订单完成
                                return self::finish($torder->torder_id, PAYMENT_ID_ALIPAY, true, '通知超时，主动查询');
                            }
                        }
                        break;
                }
            }





            $order_status_old = $torder->order_status;
            // 待支付 -> 取消
            self::check_order_status($order_status_old, T_ORDER_CANCELED);
            $torder->order_status = T_ORDER_CANCELED;
            $torder->cancel_time = $time_now;
            $torder->save();

            // 添加订单状态改变日志
            TicketOrderLogDao::ticket_order_log($torder_id, $order_status_old, T_ORDER_CANCELED, '');

            //退还 记录年卡消费信息
            $consume_log = ChildrenPlayYearCardConsumeLog::where('torder_id', $torder_id)->first();
            if ($consume_log) {
                ChildrenPlayYearCardConsumeLog::where('torder_id', $torder_id)->update([
                    //退还年卡次数
                    'consume_status' => YEAR_CARD_BACK
                ]);
                //用过次数
                ChildrenPlayYearOrder::where('torder_id', $consume_log->year_torder_id)->decrement('used_num', $consume_log->consume_num);
                //剩余次数
                ChildrenPlayYearOrder::where('torder_id', $consume_log->year_torder_id)->increment('surplus_num', $consume_log->consume_num);
            }


            switch ($torder->order_type) {
                case ORDER_TYPE_PERSON:
                    // 散客
                    // 相关门票置为取消
                    $tickets = TicketOrderItem::select([
                        'titem_id',
                        'td_id',
                        'td_tp_id',
                        'toi_status',
                    ])->where('torder_id', $torder_id)->get();
                    $tickets->each(function ($ticket, $k) use ($torder) {
                        $toi_status_old = $ticket->toi_status;
                        $toi_status_new = TICKET_CANCELED;
                        // 验证门票状态
                        TicketOrderItemDao::check_ticket_status($toi_status_old, $toi_status_new);
                        $ticket->toi_status = $toi_status_new;
                        $ticket->save();
                        // 添加状态改变日志
                        TicketOrderItemLogDao::ticket_order_item_log($ticket->titem_id, $toi_status_old, $toi_status_new, 0, '');

                        TicketDateTimeperiod::where('td_tp_id', $ticket->td_tp_id)->decrement('tp_count');
                    });
                    break;
                case ORDER_TYPE_TEAM:
                    // 团体
                    // 修改门票状态
                    $titem_team_data = TicketOrderItemTeam::where('torder_id', $torder_id)->get([
                        'titem_team_id',
                        'td_id',
                        'td_tp_id'
                    ]);
                    foreach ($titem_team_data as $titem_team) {
                        $titem_team->toi_status = TICKET_CANCELED;
                        $titem_team->save();

                        // 释放团体预约数量
                        TicketDateTimeperiod::where('td_tp_id', $titem_team->td_tp_id)->decrement('tp_count', $torder->people_num);
                        TicketDateTimeperiod::where('td_tp_id', $titem_team->td_tp_id)->decrement('tp_count_n');
                    }

                    // 人员名单添加删除标记
                    TicketOrderTeamPlist::where('torder_id', $torder_id)->update(['is_del' => 1]);
                    break;
            }

        });
    }

    /**
     * refund_by_titem_ids
     *
     * @param $titem_ids
     * @param bool $is_admin
     * @return bool|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @author lxp 20181025
     */
    public static function refund_by_titem_ids($titem_ids, $is_admin = false)
    {
        if ($is_admin === true) {
            Auth::setDefaultDriver('adminapi');
        }
        $user = Auth::user();
        if ($user) {
            $uid = $user->uid;
        } else {
            $uid = 0;
        }
        // 验证titem_id
        $titem_ids_array = explode(',', $titem_ids);
        if (count($titem_ids_array) == 0) {
            return '数据错误，请刷新后重试';
        }

        // 取得门票信息
        $titems = TicketOrderItem::leftJoin('ticket', 'ticket.ticket_id', 'ticket_order_item.ticket_id')->whereIn('ticket_order_item.titem_id', $titem_ids_array)->get([
            'ticket_order_item.titem_id',
            'ticket_order_item.torder_id',
            'ticket_order_item.toi_status',
            'ticket_order_item.toi_id',
            'ticket_order_item.ticket_id',
            'ticket.refund_limit',
            'ticket.refund_lasttime',
            'ticket.ticket_id',
            'toi_id'
        ]);
        if (!$titems) {
            return '没有可退的门票，请刷新后重试';
        }
        $torder_id = $titems[0]->torder_id;
        if ($titems->where('torder_id', $torder_id)->count() != count($titem_ids_array)) {
            return '数据错误，请刷新后重试';
        }
        // 取得订单信息
        $torder_query = TicketOrder::where('torder_id', $torder_id);
        if ($is_admin === false) {
            $torder_query->whereIn('order_status', [
                T_ORDER_FINISH,
                T_ORDER_REFUNDED_PART
            ]);
        } else {
//			$torder_query->whereIn('order_status', [
//				T_ORDER_FINISH,
//				T_ORDER_REFUNDED_PART,
////				T_ORDER_CANCELED
//			]);
        }
        $torder = $torder_query->first([
            'torder_id',
            'payment_id',
            'out_trade_no',
            'order_sn',
            'order_amount',
            'uid',
            'contact_phone',
            't_date',
            'plat'
        ]);
        if (is_null($torder)) {
            return '订单数据错误，请刷新后重试';
        }



        // 门票验证
        foreach ($titems as $titem) {

            if ($is_admin === false) {
                // 验证门票状态，身份证的状态为待检票或待取票，其他证件为待取票
                if ($torder->plat == 'ter') {
                    if (!in_array($titem->toi_status, [TICKET_UNGET, TICKET_UNCHECK])) {
                        return '含有已过期或已取票的门票，不可退票';
                    }
                } else {
                    if (!in_array($titem->toi_status, [TICKET_UNGET])) {
                        return '含有已过期或已取票的门票，不可退票';
                    }
                }

                // 验证退票限制
                if ($titem->refund_limit == 99) {
                    return '包含不可退票的门票，不可退票';
                }
                if (date('Y-m-d', strtotime("+{$titem->refund_limit} day")) > $torder->t_date) {
                    return '包含已超过退票期限的门票，不可退票';
                }
                // 判断是否超过当日退票时间
                if ($titem->refund_lasttime && $torder->t_date == date('Y-m-d')) {
                    if (date('Y-m-d H:i') > date("Y-m-d {$titem->refund_lasttime}")) {
                        return '已超过当日可退票时间，不可退票';
                    }
                }
            }else{
                if (in_array($titem->toi_status, [TICKET_REFUNDED])) {
                    return '含有已退票的门票，不可退票,请刷新后重试';
                }
            }
        }
        $uinfo = Users::where('uid', $torder->uid)->first([
            'uid',
            'phone',
            'is_test'
        ]);
        if($is_admin==true){
            $is_test = 2;
        }else{
            if (!is_null($uinfo)) {
                $is_test=$uinfo->is_test;
            }else{
                //后台退票
                $is_test = 2;
            }
        }


        // 初始化退票金额
        $refund_amount = 0;
        foreach ($titems as $t) {
            // 循环退票
            $refund_amount += self::refund($t->titem_id, $is_test);
        }
        $out_request_no = '';
        // 发起退款
        if ($refund_amount > 0 && $torder->payment_id > 0 && $torder->out_trade_no) {
            // TODO 测试支付
//            if($is_test==1){
//                $refund_amount = 0.01;
//            }

            // 退款流水单号
            $out_request_no = $torder->out_trade_no . 'R' . rand(1000, 9999);

            // 生成退款订单
            $ticket_order_refund_log = new TicketOrderRefundLog();
            $ticket_order_refund_log->torder_id = $torder_id;
            $ticket_order_refund_log->titem_ids = implode(',', $titem_ids_array);
            $ticket_order_refund_log->refund_trade_no = $out_request_no;
            if ($is_admin === false) {
                if ($uinfo) {
                    $uid = $uinfo->uid;
                } else {
                    $uid = 0;
                }
                $ticket_order_refund_log->uid = $uid;
            } else {
                $ticket_order_refund_log->admin_uid = $uid;
            }
            $ticket_order_refund_log->refund_fee = $refund_amount;
            $ticket_order_refund_log->save();

            // 取得支付方式相关信息
            $payment = TicketPayment::findOrFail($torder->payment_id);
            $payment_info = unserialize($payment->payment_info);

            switch ($torder->payment_id) {
                case PAYMENT_ID_WXPAY:
                case PAYMENT_ID_WXPAY_MINI:
                    // 微信及小程序
                    // 测试用户取得支付金额
                    $order_amount = $torder->order_amount;

                    $r = PaymentDao::wxpay_refund($payment_info, [
                        'out_trade_no' => $torder->out_trade_no,
                        'out_request_no' => $out_request_no,
                        'order_amount' => $order_amount,
                        'refund_amount' => $refund_amount
                    ], $ticket_order_refund_log);
                    if ($r !== true) {
                        return $r;
                    }
                    break;
                case PAYMENT_ID_ALIPAY:
                    // 支付宝
                    $r = PaymentDao::alipay_refund($payment_info, [
                        'out_trade_no' => $torder->out_trade_no,
                        'out_request_no' => $out_request_no,
                        'refund_amount' => $refund_amount
                    ], $ticket_order_refund_log);
                    if ($r !== true) {
                        return $r;
                    }
                    break;
            }


        }
        // 更新退款时间和单号
        TicketOrderItem::whereIn('titem_id', $titem_ids_array)->update([
            'i_refund_time' => date('Y-m-d H:i:s'),
            'i_refund_trade_no' => $out_request_no
        ]);
        // 取得退票人姓名
        $refund_person_array = TicketVisitorInfo::whereIn('toi_id', $titems->pluck('toi_id')->toArray())->get(['toi_username'])->pluck('toi_username')->toArray();
        // 发送短信
        $smssend = new SmsSendConn();
//        [张三、李四]2019-06-18的参观门票、儿童乐园亲子票退票成功，感谢您的使用。
        $content = "[" . implode('、', $refund_person_array) . "]" . $torder->t_date . "的参观门票已成功退票，感谢您的使用";
        $a = $smssend->singleSend(['mobile' => $torder->contact_phone, 'content' => $content]);
        $logObj = app('logext');
        $logObj->init('ticket_duanxin_result');
        $logObj->logbuffer('mobile', $torder->contact_phone);
        $logObj->logbuffer('result', json_encode($a));
        $logObj->logend();

        return true;
    }

    /**
     * 散客退票（单张）
     *
     * @param int $titem_id
     * @param int $is_test 测试用户标记
     * @return mixed 门票金额
     * @author lxp 20180507
     */
    public static function refund($titem_id, $is_test = 0)
    {
        return DB::transaction(function () use ($titem_id, $is_test) {
            $time_now = date('Y-m-d H:i:s');

            // 取得门票信息
            $titem = TicketOrderItem::select([
                'titem_id',
                'torder_id',
                'td_id',
                'td_tp_id',
                'toi_status',
                'is_children_play',
                'ticket_id',
                'default_price',
                'discount_price',
                'member_price'
            ])->findOrFail($titem_id);

            // 取得订单信息
            $torder = TicketOrder::select([
                'torder_id',
                'order_status',
                'payment_id',
                't_date',
                'uid',
                'order_create_type',
                'order_sn'
            ])->findOrFail($titem->torder_id);

            // 门票状态置为退票
            $toi_status_old = $titem->toi_status;
            $toi_status_new = TICKET_REFUNDED;
            // 验证门票状态
            if ($is_test == 0) {
                TicketOrderItemDao::check_ticket_status($toi_status_old, $toi_status_new);
            }

            $titem->toi_status = $toi_status_new;
            $titem->save();
            // 添加状态改变日志
            TicketOrderItemLogDao::ticket_order_item_log($titem->titem_id, $toi_status_old, $toi_status_new, 0, '');

            // 改变订单状态
            $order_status_old = $torder->order_status;
            $order_status_new = T_ORDER_REFUNDED;
            if (TicketOrderItem::where('torder_id', $titem->torder_id)->where('toi_status', '<>', $toi_status_new)->where('titem_id', '<>', $titem->titem_id)->count() > 0) {
                // 有未退票的就变为部分退票
                $order_status_new = T_ORDER_REFUNDED_PART;
            }
            self::check_order_status($order_status_old, $order_status_new);
            $torder->order_status = $order_status_new;
            $torder->refund_time = $time_now;
            $torder->save();

            // 添加订单状态改变日志
            TicketOrderLogDao::ticket_order_log($torder->torder_id, $order_status_old, $order_status_new, '');

            // 恢复门票数量
            TicketDateTimeperiod::where('td_tp_id', $titem->td_tp_id)->decrement('tp_count');
            //儿童乐园门票 判断是否绑定年卡消费
            if ($titem->is_children_play == 2) {
                $year_consume_log = ChildrenPlayYearCardConsumeLog::where('torder_id', $titem->torder_id)->where('consume_num', '>', 0)->first();
                if ($year_consume_log) {
                    ChildrenPlayYearCardConsumeLog::where('torder_id', $titem->torder_id)->decrement('consume_num');
                    ChildrenPlayYearOrder::where('torder_id', $year_consume_log->year_torder_id)->decrement('used_num');
                    ChildrenPlayYearOrder::where('torder_id', $year_consume_log->year_torder_id)->increment('surplus_num');
                    ChildrenPlayYearCardConsumeLog::where('torder_id', $titem->torder_id)->decrement('discount_price_count', $titem->discount_price);
                    $year_consume_log_new = ChildrenPlayYearCardConsumeLog::where('torder_id', $titem->torder_id)->first();
                    if ($year_consume_log_new->consume_num == 0 && $year_consume_log_new->discount_price_count == 0) {
                        ChildrenPlayYearCardConsumeLog::where('torder_id', $titem->torder_id)->update([
                            'consume_status' => YEAR_CARD_BACK
                        ]);
                    }
                    $titem->discount_price = 0;
                }

            }

            // 返回门票金额
            return $titem->discount_price;
        });
    }



    /**
     * 未支付订单检查，每分钟运行一次
     *
     * @author lxp 20170830
     */
    public static function unpay_check()
    {
        // 散客付款时间为30分钟
        $unpay_orders = TicketOrder::where([
            'order_type' => ORDER_TYPE_PERSON,
            'order_status' => T_ORDER_UNPAY
        ])->where('add_time', '<', date('Y-m-d H:i:s', strtotime('-30 minutes')))->get([
            'torder_id',
            'payment_id',
            'out_trade_no',
            'order_type',
            'is_parent'
        ]);
        $unpay_orders->each(function ($order) {
            self::unpay_cancel($order);
        });

        // 团体付款时间为12小时
        $unpay_orders_team = TicketOrder::where([
            'order_type' => ORDER_TYPE_TEAM,
            'order_status' => T_ORDER_UNPAY
        ])->where('ck_time', '<', date('Y-m-d H:i:s', strtotime('-12 hours')))->get([
            'torder_id',
            'payment_id',
            'out_trade_no',
            'order_type'
        ]);
        $unpay_orders_team->each(function ($order) {
            self::unpay_cancel($order);
        });
    }

    /**
     * 取消未支付的订单及门票
     *
     * @param object $torderObj 门票订单对象
     * @author lxp 20180509
     */
    private static function unpay_cancel($torderObj)
    {
        DB::transaction(function () use ($torderObj) {
            // 取得支付方式
            $payment = TicketPayment::select(['payment_info'])->find($torderObj->payment_id);
            if (!is_null($payment)) {
                $payment_info = unserialize($payment->payment_info);

                // 到支付平台查询订单状态
                switch ($torderObj->payment_id) {
                    case PAYMENT_ID_WXPAY:
                        $wxapp = Factory::payment([
                            'app_id' => $payment_info['wxAppId'],
                            'mch_id' => $payment_info['wxMchId'],
                            'key' => $payment_info['wxkey']
                        ]);
                        // 判断外部订单状态
                        if ($torderObj->out_trade_no) {
                            $query_result = $wxapp->order->queryByOutTradeNumber($torderObj->out_trade_no);
                            if (isset($query_result['return_code']) && $query_result['return_code'] == 'SUCCESS' && isset($query_result['trade_state']) && $query_result['trade_state'] == 'SUCCESS') {
                                // 支付成功，订单完成
                                return self::finish($torderObj->torder_id, PAYMENT_ID_WXPAY, true, '通知超时，主动查询');
                            }
                        }
                        break;
                    case PAYMENT_ID_ALIPAY:
                        $alipay = new \App\Utilities\Alipay\AopClient();
                        $alipay->appId = $payment_info['appId'];
                        $alipay->signType = 'RSA2';
                        $alipay->rsaPrivateKey = file_get_contents($payment_info['private_key_path']);
                        $alipay->alipayrsaPublicKey = file_get_contents($payment_info['public_key_path']);
                        $alipay_query = new \App\Utilities\Alipay\Request\AlipayTradeQueryRequest();
                        $data['out_trade_no'] = $torderObj->out_trade_no;
                        $alipay_query->setBizContent(json_encode($data));
                        $result = $alipay->execute($alipay_query);
                        $responseNode = str_replace(".", "_", $alipay_query->getApiMethodName()) . "_response";
                        $resultCode = $result->$responseNode->code;
                        if (!empty($resultCode) && $resultCode == 10000) {
                            $resultStatus = $result->$responseNode->trade_status;
                            if(in_array($resultStatus,["TRADE_SUCCESS","TRADE_FINISHED"])){
                                // 支付成功，订单完成
                                return self::finish($torderObj->torder_id, PAYMENT_ID_ALIPAY, true, '通知超时，主动查询');
                            }
                        }
                        break;
                }
            }

            // 订单状态变为取消
            $torderObj->order_status = T_ORDER_CANCELED;
            $torderObj->cancel_time = date('Y-m-d H:i:s');
            $torderObj->save();
            // 添加状态改变日志
            TicketOrderLogDao::ticket_order_log($torderObj->torder_id, T_ORDER_UNPAY, T_ORDER_CANCELED, 'system crontab');

            switch ($torderObj->order_type) {
                case ORDER_TYPE_PERSON:
                    // 散客
                    // 相关门票置为取消
                    $titems = TicketOrderItem::where('torder_id', $torderObj->torder_id)->get([
                        'titem_id',
                        'toi_status',
                        'td_id',
                        'td_tp_id'
                    ]);
                    $titems->each(function ($titem, $k) use ($torderObj) {
                        $toi_status_old = $titem->toi_status;
                        $titem->toi_status = TICKET_CANCELED;
                        $titem->save();
                        // 添加状态改变日志
                        TicketOrderItemLogDao::ticket_order_item_log($titem->titem_id, $toi_status_old, TICKET_CANCELED, 0, 'system crontab');
                        // 恢复门票数量
                        TicketDateTimeperiod::where('td_tp_id', $titem->td_tp_id)->decrement('tp_count');
                    });
                    break;
                case ORDER_TYPE_TEAM:
                    // 团体
                    // 修改门票状态
                    $titem_team_data = TicketOrderItemTeam::where('torder_id', $torderObj->torder_id)->get([
                        'titem_team_id',
                        'td_id',
                        'td_tp_id'
                    ]);
                    foreach ($titem_team_data as $titem_team) {
                        $titem_team->toi_status = TICKET_CANCELED;
                        $titem_team->save();

                        // 释放团体预约数量
                        TicketDateTimeperiod::where('td_tp_id', $titem_team->td_tp_id)->decrement('tp_count', $torderObj->people_num);
                        TicketDateTimeperiod::where('td_tp_id', $titem_team->td_tp_id)->decrement('tp_count_n');
                    }

                    // 人员名单添加删除标记
                    TicketOrderTeamPlist::where('torder_id', $torderObj->torder_id)->update(['is_del' => 1]);
                    break;
            }

            if (!is_null($payment)) {
                // 通知支付平台取消订单
                switch ($torderObj->payment_id) {
                    case PAYMENT_ID_WXPAY:
                        if ($torderObj->out_trade_no) {
                            $wxapp->order->close($torderObj->out_trade_no);
                        }
                        break;
                }
            }
        });
    }

    /**
     * 检查订单状态是否可更改
     *
     * @param int $old_status 原订单状态
     * @param int $new_status 新订单状态
     * @return bool
     * @throws ApiErrorException
     * @author lxp 20170823
     */
    public static function check_order_status($old_status, $new_status)
    {
        $order_status_allow = [
            T_ORDER_UNCHECKED => [
                T_ORDER_UNPAY,
                T_ORDER_CANCELED,
                T_ORDER_REFUSE
            ],
            T_ORDER_UNPAY => [
                T_ORDER_FINISH,
                T_ORDER_CANCELED
            ],
            T_ORDER_FINISH => [
                T_ORDER_REFUNDED,
                T_ORDER_FINISH,
                T_ORDER_REFUNDED_PART
            ],
            T_ORDER_CANCELED => [
                // 取消的订单仍可再支付成功，主要用于支付异步通知处理
                T_ORDER_FINISH
            ],
            T_ORDER_FAIL => [
                T_ORDER_FINISH,
                T_ORDER_CANCELED
            ],
            T_ORDER_REFUNDED => [],
            T_ORDER_REFUNDED_PART => [
                T_ORDER_REFUNDED,
                T_ORDER_REFUNDED_PART
            ],
            T_ORDER_REFUSE => [],
        ];

        if (isset($order_status_allow[$old_status]) && in_array($new_status, $order_status_allow[$old_status])) {
            return true;
        } else {
            throw new ApiErrorException('订单状态错误');
        }
    }

    /**
     * 团体订单审核通过
     *
     * @param int $torder_id
     * @param string $team_order_mark
     * @return mixed
     * @author lxp 20180515
     */
    public static function check($torder_id, $team_order_mark = '')
    {
        return DB::transaction(function () use ($torder_id, $team_order_mark) {
            $time_now = date('Y-m-d H:i:s');

            // 修改订单状态
            $torder = TicketOrder::where([
                'order_type' => ORDER_TYPE_TEAM,
                'order_status' => T_ORDER_UNCHECKED
            ])->select([
                'torder_id',
                'order_status',
                'order_amount'
            ])->findOrFail($torder_id);
            $order_status_old = $torder->order_status;
            // 待审核 -> 待支付
            self::check_order_status($order_status_old, T_ORDER_UNPAY);
            $torder->order_status = T_ORDER_UNPAY;
            $torder->ck_time = $time_now;
            $torder->save();
            // 添加状态改变日志
            TicketOrderLogDao::ticket_order_log($torder_id, $order_status_old, T_ORDER_UNPAY, $team_order_mark);

            // 改变所有门票状态
            TicketOrderItemTeam::where('torder_id', $torder_id)->update(['toi_status' => TICKET_UNPAY]);

            // 金额为0，则完成订单
            if ($torder->order_amount == 0) {
                return self::finish($torder_id);
            } else {
                return $torder;
            }
        });
    }

    /**
     * 团体订单审核不通过
     *
     * @param int $torder_id
     * @param string $team_order_mark
     * @return mixed
     * @author lxp 20180515
     */
    public static function uncheck($torder_id, $team_order_mark)
    {
        return DB::transaction(function () use ($torder_id, $team_order_mark) {
            $time_now = date('Y-m-d H:i:s');

            // 修改订单状态
            $torder = TicketOrder::where([
                'order_type' => ORDER_TYPE_TEAM,
                'order_status' => T_ORDER_UNCHECKED
            ])->select([
                'torder_id',
                'order_status',
                'people_num',
                'uid'
            ])->findOrFail($torder_id);
            $order_status_old = $torder->order_status;
            // 待审核 -> 拒绝
            self::check_order_status($order_status_old, T_ORDER_REFUSE);
            $torder->order_status = T_ORDER_REFUSE;
            $torder->ck_time = $time_now;
            $torder->save();
            // 添加状态改变日志
            TicketOrderLogDao::ticket_order_log($torder_id, $order_status_old, T_ORDER_REFUSE, $team_order_mark);

            // 保存拒绝原因和状态
            TicketOrderItemTeam::where('torder_id', $torder_id)->update([
                'team_order_mark' => $team_order_mark,
                'toi_status' => TICKET_REFUSE
            ]);

            $titems = TicketOrderItemTeam::where('torder_id', $torder_id)->get([
                'titem_team_id',
                'td_id',
                'td_tp_id'
            ]);
            foreach ($titems as $titem) {
                // 释放团体预约人数
                TicketDateTimeperiod::where('td_tp_id', $titem->td_tp_id)->decrement('tp_count', $torder->people_num);
                // 释放团体预约个数
                TicketDateTimeperiod::where('td_tp_id', $titem->td_tp_id)->decrement('tp_count_n');
            }

            // 人员名单添加删除标记
            TicketOrderTeamPlist::where('torder_id', $torder_id)->update(['is_del' => 1]);

            // 取得手机号
            $phone = Users::where('uid', $torder->uid)->value('phone');
            // 取得团体名称
            $teamname = TeamInfo::where('uid', $torder->uid)->value('teamname');
            // 发送通知短信
            $torder->sendYyFailedNotificationTeam($phone, $teamname, $team_order_mark);

            return $torder;
        });
    }


    /**
     * 年卡未支付订单检查，每分钟运行一次
     *
     * @author lxp 20170830
     */
    public static function year_card_unpay_check()
    {
        // 散客付款时间为30分钟
        $unpay_orders = ChildrenPlayYearOrder::where([
            'order_status' => T_ORDER_UNPAY
        ])->where('add_time', '<', date('Y-m-d H:i:s', strtotime('-30 minutes')))->get([
            'torder_id',
            'payment_id',
            'out_trade_no'
        ]);
        foreach ($unpay_orders as $k => $order) {
            // 订单状态变为取消
            $order->order_status = T_ORDER_CANCELED;
            $order->cancel_time = date('Y-m-d H:i:s');
            $order->save();
            ChildrenPlayYear::where('cpy_id', $order->cpy_id)->decrement('yy_count');
        }


    }

    /**
     * 门票年卡未支付订单检查，每分钟运行一次
     *
     * @author lxp 20170830
     */
    public static function ticket_year_card_unpay_check()
    {
        // 散客付款时间为30分钟
        $unpay_orders = TicketYearCardOrder::where([
            'order_status' => T_ORDER_UNPAY
        ])->where('add_time', '<', date('Y-m-d H:i:s', strtotime('-30 minutes')))->get([
            'torder_id',
            'payment_id',
            'out_trade_no'
        ]);
        foreach ($unpay_orders as $k => $order) {
            // 订单状态变为取消
            $order->order_status = T_ORDER_CANCELED;
            $order->cancel_time = date('Y-m-d H:i:s');
            $order->save();
            TicketYearCard::where('tyc_id', $order->tyc_id)->decrement('yy_count');
        }


    }


}
